package com.knowswift.common.common;


import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.fasterxml.jackson.annotation.JsonIgnore;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

/**
 * 定制 mybatis-plus 的分页组件
 * 1. 新增：current、size参数类型为装箱Long的构造器
 * 用于接收前端分页参数时，允许为空
 * <p>
 * 2. 新增：包含defaultCurrent，defaultSize参数的构造器，用于指定缺少current、size参数时的默认值。（默认为1，10）
 * <p>
 * 3. 安全创建
 *
 * @param <T>
 */

public class Page<T> implements IPage<T> {
    private static final long serialVersionUID = 8545996863226528798L;
    private List<T> records;
    private long total;
    private long size;
    private long current;
    private boolean isPage;
    @JsonIgnore
    private List<OrderItem> orders;
    @JsonIgnore
    private boolean optimizeCountSql;
    @JsonIgnore
    private boolean isSearchCount;

    public Page() {
        this.records = Collections.emptyList();
        this.total = 0L;
        this.size = 10L;
        this.current = 1L;
        this.orders = new ArrayList<>();
        this.optimizeCountSql = true;
        this.isSearchCount = true;
    }

    public Page(Long current, Long size) {
        this(current, size, 1L, 10L);
    }

    public Page(Long current, Long size, long defaultCurrent, long defaultSize) {
        this(current, size, defaultCurrent, defaultSize, 0L, true);
    }

    public Page(Long current, Long size, long total) {
        this(current, size, 1L, 10L, total);
    }

    public Page(Long current, Long size, long defaultCurrent, long defaultSize, long total) {
        this(current, size, defaultCurrent, defaultSize, total, true);
    }

    public Page(Long current, Long size, boolean isSearchCount) {
        this(current, size, 1L, 10L, isSearchCount);
    }

    public Page(Long current, Long size, long defaultCurrent, long defaultSize, boolean isSearchCount) {
        this(current, size, defaultCurrent, defaultSize, 0L, isSearchCount);
    }

    public Page(Long current, Long size, long total, boolean isSearchCount) {
        this(current, size, 1L, 10L, total, isSearchCount);
    }

    public Page(Long current, Long size, long defaultCurrent, long defaultSize, long total, boolean isSearchCount) {
        isPage = current != null && current.compareTo(1L) >= 0;
        this.current = !isPage ? defaultCurrent : current;
        long l = size == null ? defaultSize : size;
        this.size = defaultSize;
        this.records = Collections.emptyList();
        this.orders = new ArrayList<>();
        this.optimizeCountSql = true;
        if (this.current < 1L) {
            this.current = 1L;
        }
        if (l > 1L) {
            this.size = l;
        }
        this.total = total;
        this.isSearchCount = isSearchCount;
    }

    public boolean hasPrevious() {
        return this.current > 1L;
    }

    public boolean hasNext() {
        return this.current < this.getPages();
    }

    public List<T> getRecords() {
        return this.records;
    }

    public Page<T> setRecords(List<T> records) {
        this.records = records;
        return this;
    }

    public long getTotal() {
        return this.total;
    }

    public Page<T> setTotal(long total) {
        this.total = total;
        if (!isPage) {
            this.size = total;
        }
        return this;
    }

    public long getSize() {
        return this.size;
    }

    public Page<T> setSize(long size) {
        this.size = size;
        return this;
    }

    public long getCurrent() {
        return this.current;
    }

    public Page<T> setCurrent(long current) {
        this.current = current;
        return this;
    }

    private void removeOrder(Predicate<OrderItem> filter) {
        for (int i = this.orders.size() - 1; i >= 0; --i) {
            if (filter.test(this.orders.get(i))) {
                this.orders.remove(i);
            }
        }

    }

    public Page<T> addOrder(OrderItem... items) {
        this.orders.addAll(Arrays.asList(items));
        return this;
    }

    public Page<T> addOrder(List<OrderItem> items) {
        this.orders.addAll(items);
        return this;
    }


    public List<OrderItem> orders() {
        return this.getOrders();
    }

    public List<OrderItem> getOrders() {
        return this.orders;
    }

    public void setOrders(List<OrderItem> orders) {
        this.orders = orders;
    }

    public boolean optimizeCountSql() {
        return this.optimizeCountSql;
    }

    public boolean isSearchCount() {
        return this.total >= 0L && this.isSearchCount;
    }

    public Page<T> setSearchCount(boolean isSearchCount) {
        this.isSearchCount = isSearchCount;
        return this;
    }

    public Page<T> setOptimizeCountSql(boolean optimizeCountSql) {
        this.optimizeCountSql = optimizeCountSql;
        return this;
    }
}

